﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using MUD.Network;
using MUD.Lib.Objects.Characters;
using MUD.Lib.Utils;

namespace MUD.Lib.Objects.Users
{
    internal partial class User : MudObject
    {
        private AsyncClient _networkClient;
        //TODO: Not everyone needs to be an admin. This is for testing only, fix it.
        private Permissions _userPermissions = Permissions.Admin;

        public delegate bool ReceiveHandler(User user, string command);
        public event ReceiveHandler OnReceive;
        public event ReceiveHandler OnExclusiveReceive;

        public Collection<Alias> Aliases = new Collection<Alias>();

        public Collection<Character> Characters = new Collection<Character>();
        public Character CurrentCharacter;

        public string Username
        {
            get { return ShortDesc; }
            set 
            { 
                ShortDesc = value;
                ID.Add(value);
            }
        }

        public string Password { get; set; }
        public string Email { get; set; }

        private Master _masterObj;
        public Master MasterObj
        {
            get { return _masterObj; }
        }

        public AsyncClient Client
        {
            get { return _networkClient; }
        }

        public User(AsyncClient client, Master mst)
        {
            _networkClient = client;
            _masterObj = mst;
            SetUpStandardAliases();
        }

        public void Write(string message)
        {
            _networkClient.Write(ANSI.ParseANSI(message));
        }

        public void Recieve(string command)
        {
            command = ProcessAliases(command.TrimNewline());

            bool Intercepted = false;
            // first, if another object is listening exclusively to this user, block everyone and everything else off and let them:
            if (OnExclusiveReceive != null)
            {
                OnExclusiveReceive(this, command);
                Intercepted = true;
            }
            // if another object is listening to this user, make sure to let that object handle the command first.
            else if(OnReceive != null)
            {
                foreach (ReceiveHandler listener in OnReceive.GetInvocationList())
                {
                    try
                    {
                        Intercepted = listener(this, command);
                        if (Intercepted)
                        {
                            PrintPrompt();
                            break;
                        }
                    }
                    catch(Exception ex)
                    {
                        MasterObj.Log(ex.Message);
                    }
                }
            }
            // ok, no one else found a command like the one the user entered, so...
            if (!Intercepted)
            {
                // Send the command to the command hook.
                CommandHook.ExecuteCommand(this, command);
                PrintPrompt();
            }
        }

        private string ProcessAliases(string command)
        {
            foreach (Alias alias in Aliases)
            {
                if (alias.Command == command.NthWord(0))
                {
                    return alias.Translate(command);
                }
            }
            return command;
        }

        public bool IsAdmin()
        {
            return _userPermissions.Contains(Permissions.Admin);
        }

        public bool IsGM()
        {
            return _userPermissions.Contains(Permissions.GameMaster);
        }

        public void AddPermission(Permissions perm)
        {
            _userPermissions = _userPermissions.Add(perm);
        }

        public void RemovePermission(Permissions perm)
        {
            _userPermissions = _userPermissions.Remove(perm);
        }

        public void PrintPrompt()
        {
            //TODO: Possibly add customizable prompts.
            Write(">");
        }

        public void Disconnect()
        {
            _networkClient.Disconnect();
        }

        private void SetUpStandardAliases()
        {
            Aliases.Add(new Alias("l", "look $*"));
            Aliases.Add(new Alias("n", "north"));
            Aliases.Add(new Alias("s", "south"));
            Aliases.Add(new Alias("e", "east"));
            Aliases.Add(new Alias("w", "west"));
        }

        public override bool Move(Container target)
        {
            if (base.Move(target))
            {
                CommandHook.ExecuteCommand(this, "look");
                return true;
            }
            else
            {
                Write("Cannot move to that location!");
                return false;
            }
        }
    }
}
